﻿using Assets.Scripts.UI.Upload;
using Jinndev.Json;
using Jinndev.UI;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

namespace Jinndev {

    public class UploadUI : BaseUIBehaviour {

        #region static
        public static readonly string PATH = "Prefab/UI/Upload/UploadUI";

        /// <summary>
        /// 
        /// </summary>
        /// <param name="configPath">配置文件所处路径</param>
        /// <param name="rootPath">要上传的本地路径</param>
        public static UploadUI Create(string configPath, string rootPath) {
            var com = UIManager.Instance.Add<UploadUI>(PATH, UIParam.ModalMask);
            com.Init(configPath, rootPath);
            return com;
        }
        #endregion



        public RectTransform rootPathSlot;
        public InputField localPathInput;
        public InputField remotePathInput;
        public Button uploadBtn;
        public Button deleteBtn;
        public Image progressBar;
        public Text progressText;
        public Text sizeText;
        public Dropdown configDropdown;
        public RectTransform logArea;

        private InputFileField rootPathInput;
        private List<UploadConfig> configList = new List<UploadConfig>();

        private LogView logView;

        private IUploader uploader;

        [System.Serializable]
        public class OnSubProgress : IProgress<double> {
            public Image subProgressBar;
            public Text subProgressText;
            internal Action<Action> update;

            public void Report(double value) {
                update(() => {
                    subProgressBar.fillAmount = (float)value;
                    subProgressText.text = string.Empty;
                });
            }

            internal void Init() {
                subProgressBar.fillAmount = 0;
                subProgressText.text = string.Empty;
            }
        }
        public OnSubProgress onSubProgress = new();

        private void Awake() {
            onSubProgress.update = EnqueueAction;
            onSubProgress.Init();

            configDropdown.ClearOptions();
            configDropdown.onValueChanged.AddListener((value) => OnConfigChanged());

            progressBar.fillAmount = 0;
            progressText.text = string.Empty;
            sizeText.text = string.Empty;

            logView = LogView.Create(logArea);
            rootPathInput = InputFileField.Create(rootPathSlot, new InputFileField.DirectoryOption("根文件夹", "选择需要上传的本地路径", OnChooseRootPath));

            UIUtil.AddButtonClick(remotePathInput, "ButtonPaste", () => remotePathInput.text = GUIUtility.systemCopyBuffer);
            UIUtil.AddButtonClick(remotePathInput, "ButtonClear", () => remotePathInput.text = string.Empty);
        }

        private void OnDestroy() {
            uploader?.Dispose();
        }

        private void Update() {
            TryInvokeAllActions();
        }

        private void Init(string configPath, string rootPath) {
            //// 寻找remote的父目录
            //var dir = new DirectoryInfo(rootPath);
            //if (dir.Name == "remote")
            //{
            //    rootPath = dir.Parent.FullName;
            //}
            FindConfig(configPath);
            rootPathInput.SetPath(rootPath, true);
            OnConfigChanged();
        }

        private void OnChooseRootPath(string path) {
            
        }

        private void OnConfigChanged() {
            int value = configDropdown.value;
            if (value < configList.Count) {
                var config = configList[value];
                localPathInput.text = Path.Combine(rootPathInput.GetPath(), config.localPath);
                remotePathInput.text = config.remotePath;
            }
            else {
                localPathInput.text = string.Empty;
                remotePathInput.text = string.Empty;
            }
            deleteBtn.gameObject.SetActive(value < configList.Count && configList[value].type == "sync");
        }

        public void OnClickUpload() {
            StartProcess("Upload");
        }

        public void OnClickDelete() {
            StartProcess("Delete");
        }

        private void StartProcess(string method) {
            progressBar.fillAmount = 0;
            progressText.text = string.Empty;
            sizeText.text = string.Empty;

            if (uploader?.uploading == true) {
                logView.LogError("正在进行中");
                return;
            }
            if (uploader != null) {
                uploader = null;
            }

            if (configList.Count == 0 || configDropdown.value >= configList.Count) {
                logView.LogError("没有找到配置");
                return;
            }
            string localPath = localPathInput.text;
            if (string.IsNullOrEmpty(localPath) || !Directory.Exists(localPath)) {
                logView.LogError("本地路径不存在");
                logView.LogError(localPath);
                return;
            }

            UploadConfig config = configList[configDropdown.value];
            if (config.type == "sync") {
                uploader = new SyncUploader(config, localPath);
            }
            else {
                uploader = new FtpUploader(config, localPath);
            }

            uploader.Log += (obj) => EnqueueAction(() => {
                if (obj is Exception e) {
                    logView.LogException(e);
                }
                else {
                    logView.Log(obj.ToString());
                }
            });
            uploader.Progress += SetProgressLater;
            uploader.SubProgress += (progress) => {
                EnqueueAction(() => {
                    if (progress == 0) {
                        onSubProgress.Init();
                    }
                    else {
                        onSubProgress.Report(progress);
                    }
                });
            };
            uploader.Complete += () => {
                EnqueueAction(() => {
                    uploadBtn.interactable = true;
                    deleteBtn.interactable = true;
                });
            };

            uploadBtn.interactable = false;
            deleteBtn.interactable = false;

            if (method == "Upload") {
                uploader.StartUpload();
            }
            else if (method == "Delete") {
                (uploader as SyncUploader).StartDeleteExcludeFiles();
            }
            else {
                uploadBtn.interactable = true;
                deleteBtn.interactable = true;
                return;
            }
        }

        private void SetProgressLater(int index, int total, long totalSize) {
            EnqueueAction(() => {
                progressBar.fillAmount = total == 0 ? 0 : (float)index / total;
                progressText.text = (index) + "/" + total;
                sizeText.text = CommonUtil.GetFileSizeDesc(totalSize);
            });
        }

        private void FindConfig(string configPath) {
            configList.Clear();

            if (Directory.Exists(configPath)) {
                //Debug.Log(new DirectoryInfo(localPath).Parent);

                FileInfo[] files = new DirectoryInfo(configPath).GetFiles("FtpUploader*.json", SearchOption.TopDirectoryOnly);
                if (files.Length == 0) {
                    files = new DirectoryInfo(configPath).Parent.GetFiles("FtpUploader*.json", SearchOption.TopDirectoryOnly);
                }

                foreach (var file in files) {
                    var config = JsonUtil.Deserialize<UploadConfig>(File.ReadAllText(file.FullName));
                    config.configName = file.Name;
                    configList.Add(config);
                }
            }

            configDropdown.ClearOptions();
            if (configList.Count > 0) {
                foreach (UploadConfig config in configList) {
                    string text = $"[{config.configName}] {config.Protocal}";
                    configDropdown.options.Add(new Dropdown.OptionData(text));
                }
                configDropdown.value = 0;
            }
        }

    }

    public class UploadConfig {
        public string configName;

        public string type;
        public string host;
        public int port;
        public string sign;
        public string username;
        public string password;
        public string localPath;
        public string remotePath;

        public string Type {
            get {
                if (string.IsNullOrEmpty(type)) {
                    return "ftp";
                }
                return type;
            }
        }

        public string Protocal {
            get {
                return $"{Type}://{host}:{port}/{(remotePath.StartsWith("/") ? remotePath.Substring(1) : remotePath)}";
            }
        }

    }

}
